/*
 ------------------------------------------------------------------------------
 Copyright (C) 2013 Eternal Games.

 This file is part of the EternalTech source code.

 The EternalTech source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The EternalTech source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the EternalTech source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// entFile.cpp - entity file parsing and writing (this is only for light and speaker entities at the moment)
//


#include "game.h"


/*
 ==================
 etEntFile::etEntFile
 ==================
*/
etEntFile::etEntFile (){

	numEntities = 0;
	glqMemory->Fill(entities, 0, sizeof(entities));
}

/*
 ==================
 etEntFile::~etEntFile
 ==================
*/
etEntFile::~etEntFile (){

	entEntity_t	*entity;
	int			i;

	for (i = 0, entity = entities; i < numEntities; i++, entity++)
		entity->dict.Clear();
}

/*
 ==================
 etEntFile::Clear
 ==================
*/
void etEntFile::Clear (){

	entEntity_t	*entity;
	int			i;

	for (i = 0, entity = entities; i < numEntities; i++, entity++){
		entity->used = false;
		entity->dict.Clear();
	}

	numEntities = 0;
	glqMemory->Fill(entities, 0, sizeof(entities));
}

/*
 ==================
 etEntFile::Parse
 ==================
*/
bool etEntFile::Parse (const char *name){

	script_t	*script;
	entEntity_t	*entity;

	Clear();

	// Load the script file
	script = glqParser->LoadScriptFile(name);
	if (!script){
		G_Printf("Couldn't parse %s\n", name);
		return false;
	}

	glqParser->SetScriptFlags(script, SF_NOFATALERRORS);

	// Parse the entities
	while (1){
		if (!glqParser->TokenAvailable(script, true))
			break;

		if (numEntities == MAX_ENT_ENTITIES){
			glqParser->ScriptError(script, "too many entities");
			glqParser->FreeScript(script);

			Clear();

			return false;
		}

		entity = &entities[numEntities++];

		if (!entity->dict.Parse(script)){
			glqParser->FreeScript(script);

			Clear();

			return false;
		}

		entity->used = true;
	}

	glqParser->FreeScript(script);

	return true;
}

/*
 ==================
 etEntFile::Write
 ==================
*/
bool etEntFile::Write (const char *name) const {

	fileHandle_t		f;
	const entEntity_t	*entity;
	int					i;

	// Open the entity file
	glqFileSystem->OpenFile(name, FS_WRITE, &f);
	if (!f){
		G_Printf("Couldn't write %s\n", name);
		return false;
	}

	// Write the entities
	for (i = 0, entity = entities; i < numEntities; i++, entity++){
		if (!entity->used)
			continue;

		entity->dict.Write(f);
	}

	glqFileSystem->CloseFile(f);

	return true;
}

/*
 ==================
 etEntFile::AddEntity
 ==================
*/
void etEntFile::AddEntity (const etDict &dict){

	entEntity_t	*entity;
	int			i;

	// Try to find an unused entity
	for (i = 0, entity = entities; i < numEntities; i++, entity++){
		if (!entity->used)
			break;
	}

	// If we didn't find an unused entity, allocate a new one
	if (i == numEntities){
		if (numEntities == MAX_ENT_ENTITIES)
			return;

		entity = &entities[numEntities++];
	}

	// Add it
	entity->used = true;
	entity->dict = dict;
}

/*
 ==================
 etEntFile::RemoveEntity
 ==================
*/
void etEntFile::RemoveEntity (const char *name){

	entEntity_t	*entity;
	int			i;

	for (i = 0, entity = entities; i < numEntities; i++, entity++){
		if (!entity->used)
			continue;

		if (!Str_ICompare(entity->dict.GetString("name"), name)){
			entity->used = false;
			entity->dict.Clear();

			break;
		}
	}
}

/*
 ==================
 etEntFile::RemoveEntities
 ==================
*/
void etEntFile::RemoveEntities (const char *className){

	entEntity_t	*entity;
	int			i;

	for (i = 0, entity = entities; i < numEntities; i++, entity++){
		if (!entity->used)
			continue;

		if (!Str_ICompare(entity->dict.GetString("className"), className)){
			entity->used = false;
			entity->dict.Clear();
		}
	}
}

/*
 ==================
 etEntFile::RemoveAllEntities
 ==================
*/
void etEntFile::RemoveAllEntities (){

	entEntity_t	*entity;
	int			i;

	for (i = 0, entity = entities; i < numEntities; i++, entity++){
		if (!entity->used)
			continue;

		entity->used = false;
		entity->dict.Clear();
	}

	numEntities = 0;
}